using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using BehaviorDesigner.Runtime.Tasks.Unity.UnityParticleSystem;
using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Core.Easing;
using QFramework;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.UI;


public class Snake : MonoBehaviour,IController,ICanSendEvent
{
    public Rigidbody2D rigidbody2D;
    public float speed = 5f;
    public float initSpeed = 10f;
    public GameObject joint;
    public float reduceSpeed = 0.2f;

    public int initLenght = 5;
    public bool isStart = false; 
    public List<HingeJoint2D> joint2Ds = new List<HingeJoint2D>();
    public float bloomSpeed = 50f;
    public float zeroTime = 0;
    public float winIndex = 0;
    public bool isGameOver = false;

    public float maxSpeed = 500f;
    
    private void Awake() 
    {

        
    }

    private void Start()
    {
        this.RegisterEvent<GameInitFinish>(OnGameInitFinish).UnRegisterWhenGameObjectDestroyed(gameObject);
        this.RegisterEvent<GameStart>(OnGameStart).UnRegisterWhenGameObjectDestroyed(gameObject);
        rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
    }

    [Button]
    public void AddLenth(bool isInit = true)
    {
        GameObject joint = Instantiate<GameObject>(this.joint);
        joint.transform.SetParent(this.transform);
        var jointComponet = joint.GetComponent<HingeJoint2D>();
        Transform lastTransform;
        if (joint2Ds.Count == 0)
        {
            jointComponet.connectedBody = rigidbody2D;
            lastTransform = this.transform;
            joint.transform.position = lastTransform.position + (rigidbody2D.velocity.x > 0 ? Vector3.right : Vector3.left) * 1.15f;
        }
        else
        {
            var last = joint2Ds.Last();
            var rigidbody2D = last.gameObject.GetComponent<Rigidbody2D>();
            jointComponet.connectedBody = rigidbody2D;
            lastTransform = last.gameObject.transform;
            Vector3 vector;
            if (joint2Ds.Count == 1)
            {
                vector = last.transform.position - this.transform.position;
            }
            else
            {
                var lastLast = joint2Ds[joint2Ds.Count - 2];
                vector = last.transform.position - lastLast.transform.position;
            }
            joint.transform.position = lastTransform.position +  vector;
        }

        if (Application.isPlaying && !isInit)
        {
            joint.transform.localScale = Vector3.zero;
            joint.transform.DOScale(Vector3.one, 1);
        }
        joint2Ds.Add(jointComponet);
    }

    public void Reset()
    {
        for (int i = joint2Ds.Count - 1; i >= initLenght; i--)
        {
            var gameObject = joint2Ds[i].gameObject;
            Destroy(gameObject);
        }

        var initCount = initLenght - joint2Ds.Count;
        for (int i = 0; i < initCount; i++)
        {
            AddLenth(true);
        }

        // foreach (var joint2D in joint2Ds)
        // {
        //     joint2D.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
        // }
    }
    
    private void FixedUpdate() 
    {
        if (! isStart || isGameOver) return;
        
#if UNITY_EDITOR
        if (Input.GetKey(KeyCode.D))
        {
            rigidbody2D.velocity = Vector2.right * speed; 
            // var position = rigidbody2D.position;
            // position.x += speed;
            // rigidbody2D.MovePosition(position);
        }
        if (Input.GetKey(KeyCode.A))
        {
            rigidbody2D.velocity = Vector2.left * speed; 
        }
#endif
        var velocity = rigidbody2D.velocity;
        
        if (velocity.magnitude < 1)
        {

            zeroTime = zeroTime + Time.fixedDeltaTime;
            if (zeroTime > 3f)
            {
                Debug.Log("Fail");
                GameOver(false);
            }
        }
        else
        {
            zeroTime = 0;
        }

        AddSpeed(-reduceSpeed);
    }

    public void AddSpeed(float speed)
    {
        
        var velocity = rigidbody2D.velocity;
        speed = Math.Min( maxSpeed - (float)velocity.magnitude, speed);
        if (velocity.magnitude > -speed)
        {
            var addSpeed = velocity.normalized * speed; ;
            rigidbody2D.velocity = velocity + addSpeed;
        }
        else
        {
            rigidbody2D.velocity = Vector2.zero;
        }

    }
        // rigidbody2D.AddForce(addForce);
    
    private void AddSpeed(float speed, Vector2 dir)
    {
        speed = Math.Min( maxSpeed - (float)rigidbody2D.velocity.magnitude, speed);
        var velocity = rigidbody2D.velocity * dir;
        var addSpeed = speed * dir;
        velocity.x = velocity.x + addSpeed.x;
        velocity.y =  velocity.y + addSpeed.y;  
        rigidbody2D.velocity = velocity;
    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        if (!isStart || isGameOver) return;
        if (other.gameObject.tag == "Player")
        {
            
            for (int i = 0; i < joint2Ds.Count; i++)
            {
                var gameObject = joint2Ds[i].gameObject;
                if (gameObject == other.gameObject && i >= 2)
                {
                    Debug.Log("Win");
                    GameOver(true);
                }
            }
            
 
        }

        if (other.gameObject.tag == "Trap")
        {
            Debug.Log("Fail");
            GameOver(false);
        }
    }

    void GameOver(bool isSuccess)
    {
        if (isGameOver) return;
        if (isSuccess)
        {
            this.GetComponent<Collider2D>().enabled = false;
            this.rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
            this.rigidbody2D.velocity = Vector2.zero;
            foreach (var joint in joint2Ds)
            {
                var rigidbody = joint.gameObject.GetComponent<Rigidbody2D>();
            
                rigidbody.GetComponent<Collider2D>().enabled = false;
                rigidbody.bodyType = RigidbodyType2D.Kinematic;
                rigidbody.velocity = Vector2.zero;
                
            }
        }
        isGameOver = true;
        this.SendEvent<GameOver>(new GameOver()
        {
            isSuccess = isSuccess
        });
    }

    [Button]
    void Test()
    {
        AddSpeed( 600, Vector2.left);
    }
    private void AddForce(GameObject gameObject)
    { 
        
        var dir = (transform.position - gameObject.transform.position).normalized;
        AddSpeed(10f, dir);
        // rigidbody2D.AddForce(dir * 10, ForceMode2D.Impulse);
    }
    
    private void OnTriggerEnter2D(Collider2D other) 
    {
        if (!isStart) return;
        var component = other.gameObject.GetComponent<Food>();
        if (component)
        {
            component.DoAction(this);
        }
    }
    private void OnGameInitFinish(GameInitFinish gameInitFinish)
    {
        rigidbody2D.bodyType = RigidbodyType2D.Dynamic;
        Reset();
        foreach (var joint in joint2Ds)
        {
            joint.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
        }
    }

    [Button]
    private void OnGameStart(GameStart gameStartEvent)
    {
        this.isStart = true;
        AddSpeed(initSpeed, Vector2.right);
        // rigidbody2D.velocity = Vector2.right * initSpeed;
        
    }

    public IArchitecture GetArchitecture() => GameArchitecture.Interface;
}
